package com.comp6231.frontend;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;

/**
 * 
 * This is the class which extents thread and implements the run method.
 * 
 * This thread is created for each client request and this sends a UDP message
 * to the coordinator and wait for its reply.
 * 
 * @author sknarula (narula.sk@gmail.com)
 * @since November 2013
 * 
 * 
 */
public class ProcessClientRequest {

	/**
	 * String message to be send to coordinator
	 */
	private String message;

	/**
	 * request id in hash table for this thread
	 */
	private int requestId;

//	static int port = new Integer(
//			FrontEndInitiator.frontEnd_UDPPort_data);
//	
	/**
	 * 
	 * @param message
	 */
	public ProcessClientRequest(String message, int requestId) {
		this.message = message;
		this.requestId = requestId;
	}

	public void process() {
		DatagramSocket aSocket = null;
		DatagramPacket reply = null;
		try {
			boolean continueSending = true;			
			aSocket = new DatagramSocket();
			
			int leaderUDPPort = FrontEndInitiator.leaderUDPPort;
			
			// loop to re-send if no reply within a set time period
			while (continueSending) {

				// in case leader change between requests, reload it UDP port
				if (leaderUDPPort != FrontEndInitiator.leaderUDPPort) {
					leaderUDPPort = FrontEndInitiator.leaderUDPPort;
				}
				
				// prepare to send message
				byte[] m = this.message.getBytes();
				InetAddress aHost = InetAddress
						.getByName(FrontEndInitiator.leaderHostName);
				int serverPort = leaderUDPPort;
				DatagramPacket request = new DatagramPacket(m,
						message.length(), aHost, serverPort);

				// send to server omitted
				aSocket.send(request);

				// prepare receive message
				byte[] buffer = new byte[1000];
				reply = new DatagramPacket(buffer, buffer.length);

				// prepare to receive reply
				aSocket.setSoTimeout(10000);

				try {
					aSocket.receive(reply);
					
					continueSending = false; // a packet has been received :
												// stop sending
				} catch (SocketTimeoutException e) {
					// no response received after 1 second. continue sending
				}

			}
			/*
			 * replace the message string in the hash table for this request id
			 * with the exact response to be sent back to client
			 */
			String serverResponse = (new String(reply.getData())).trim();
			FrontEndInitiator.clientRequests.remove(this.requestId);
			FrontEndInitiator.clientRequests
					.put(this.requestId, serverResponse);

		} catch (SocketException e) {
			// close socket and re-try
			if (aSocket != null)
				aSocket.close();
			process();
		} catch (IOException e) {
			// close socket and re-try
			if (aSocket != null)
				aSocket.close();
			process();
		
		} finally {
			// close socket
			if (aSocket != null)
				aSocket.close();
		}
		
	}

}
